using System;
using Microsoft.Win32;
using Foundation.ExtensionMethods;

namespace Foundation.FileAssotiations
{
    /// <summary>
    /// Provides instance methods for the creation, modification, and deletion of file extension associations in the Windows registry.
    /// </summary>
    public class ExtensionInfo
    {
        private const string PerceivedTypeSubKeyName = "PerceivedType";
        private const string ContentTypeSubKeyName = "Content Type";
        private const string OpenWithListSubKeyName = "OpenWithList";
        private const string PersistentHandlerSubKeyName = "PersistentHandler";

        /// <summary>
        /// Gets the extension.
        /// </summary>
        public string Extension { get; private set; }

        /// <summary>
        /// Gets or sets the program id.
        /// </summary>
        /// <value>
        /// The program id.
        /// </value>
        public string ProgramId { get; set; }

        /// <summary>
        /// Gets or sets the type of the content.
        /// </summary>
        /// <value>
        /// The type of the content.
        /// </value>
        public string ContentType { get; set; }

        /// <summary>
        /// Gets or sets the open with list.
        /// </summary>
        /// <value>
        /// The open with list.
        /// </value>
        public string[] OpenWithList { get; set; }

        /// <summary>
        /// Gets or sets the type of the perceived.
        /// </summary>
        /// <value>
        /// The type of the perceived.
        /// </value>
        public string PerceivedType { get; set; }

        /// <summary>
        /// Gets or sets the persistent handler.
        /// </summary>
        /// <value>
        /// The persistent handler.
        /// </value>
        public Guid PersistentHandler { get; set; }

        /// <summary>
        /// Deletes the specified extension.
        /// </summary>
        /// <param name="extension">The extension.</param>
        public static void Delete(string extension)
        {
            if (Registry.ClassesRoot.Exists(extension))
                Registry.ClassesRoot.DeleteSubKeyTree(extension);
        }

        /// <summary>
        /// Gets the specified extension.
        /// </summary>
        /// <param name="extension">The extension.</param>
        /// <returns></returns>
        public static ExtensionInfo Get(string extension)
        {
            extension = extension.StartsWith(".") ? extension : string.Format(".{0}", extension);
            if (!Registry.ClassesRoot.Exists(extension))
                return new ExtensionInfo { Extension = extension, PersistentHandler = new Guid() };

            var info = new ExtensionInfo
            {
                Extension = extension,
                ProgramId = Registry.ClassesRoot.GetValueByPath(extension, string.Empty) as string,
                ContentType = Registry.ClassesRoot.GetValueByPath(extension, ContentTypeSubKeyName) as string,
                PerceivedType = Registry.ClassesRoot.GetValueByPath(extension, PerceivedTypeSubKeyName) as string,
            };

            var openWithSubKey = Registry.ClassesRoot.CreateOrOpenSubKey(extension, false).OpenSubKey(OpenWithListSubKeyName);
            if (openWithSubKey != null) info.OpenWithList = openWithSubKey.GetSubKeyNames();

            var value = Registry.ClassesRoot.GetValueByPath(string.Format(@"{0}\{1}", extension, PersistentHandlerSubKeyName), string.Empty);
            info.PersistentHandler = value == null ? Guid.Empty : new Guid(value.ToString());
            return info;
        }

        /// <summary>
        /// Sets the specified info.
        /// </summary>
        /// <param name="info">The info.</param>
        public static void Set(ExtensionInfo info)
        {
            using (var key = Registry.ClassesRoot.CreateOrOpenSubKey(info.Extension, true))
            {    
                key.SetValue(string.Empty, info.ProgramId);
                if (key.OpenSubKey(OpenWithListSubKeyName) != null)
                    key.DeleteSubKeyTree(OpenWithListSubKeyName);

                using (var openWithListSubKey = key.CreateOrOpenSubKey(OpenWithListSubKeyName))
                {
                    if (info.OpenWithList != null)
                        foreach (var s in info.OpenWithList)
                            openWithListSubKey.CreateSubKey(s);
                }
            }

            Registry.ClassesRoot.SetValueByPath(info.Extension, PerceivedTypeSubKeyName, info.PerceivedType);
            Registry.ClassesRoot.SetValueByPath(info.Extension, ContentTypeSubKeyName, info.ContentType);
            Registry.ClassesRoot.SetValueByPath(string.Format(@"{0}\{1}", info.Extension, PersistentHandlerSubKeyName),
                                                string.Empty, info.PersistentHandler);
            ShellNotification.NotifyOfChange();
        }
    }
}